package com.jet.goods.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jet.core.enums.CommonDeleted;
import com.jet.core.exception.CustomException;
import com.jet.core.model.vo.PageVo;
import com.jet.core.result.ResultCode;
import com.jet.core.utils.ExcelUtil;
import com.jet.core.utils.IdUtil;
import com.jet.goods.domain.dto.CategoryDto;
import com.jet.goods.domain.dto.CategoryImportDto;
import com.jet.goods.domain.entity.GoodsCategory;
import com.jet.goods.domain.enums.CategoryLevel;
import com.jet.goods.domain.query.CategoryListQuery;
import com.jet.goods.domain.query.CategoryQuery;
import com.jet.goods.domain.query.SpuQuery;
import com.jet.goods.domain.vo.CategoryTreeVo;
import com.jet.goods.domain.vo.CategoryVo;
import com.jet.goods.domain.vo.SpuListVo;
import com.jet.goods.mapper.GoodsCategoryMapper;
import com.jet.goods.service.IGoodsCategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jet.goods.service.IGoodsSpuService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-03-04
 */
@Service
public class GoodsCategoryServiceImpl extends ServiceImpl<GoodsCategoryMapper, GoodsCategory> implements IGoodsCategoryService {

    private final IGoodsSpuService goodsSpuService;

    public GoodsCategoryServiceImpl(IGoodsSpuService goodsSpuService) {
        this.goodsSpuService = goodsSpuService;
    }

    @Override
    public GoodsCategory create(long merchantNo, CategoryDto dto) {
        dto.setPid(StrUtil.isNotBlank(dto.getPid()) ? dto.getPid() : null);
        int level = CategoryLevel.ONE.getCode();
        if (StrUtil.isNotBlank(dto.getPid())) {
            GoodsCategory parentClassify = findById(merchantNo, dto.getPid());
            if (parentClassify == null) {
                throw new CustomException(ResultCode.BAD_REQUEST, "上级分类错误");
            }
            if (parentClassify.getLevel() > CategoryLevel.ONE.getCode()) {
                throw new CustomException(ResultCode.BAD_REQUEST, "最大只能有二级分类");
            }
            level = CategoryLevel.TWO.getCode();
        }

        if (existsByName(merchantNo, null, dto.getPid(), dto.getName())) {
            throw new CustomException("分类名重复");
        }
        GoodsCategory entity = new GoodsCategory();
        BeanUtils.copyProperties(dto, entity);
        entity.setId(IdUtil.generateLower());
        entity.setMerchantNo(merchantNo);
        entity.setLevel(level);
        super.save(entity);
        return entity;
    }

    private boolean existsByName(long merchantNo, String id, String pid, String name) {
        if (StrUtil.isBlank(pid)) {
            pid = null;
        }
        Wrapper<GoodsCategory> wrapper = new LambdaQueryWrapper<GoodsCategory>()
                .eq(GoodsCategory::getMerchantNo, merchantNo)
                .eq(GoodsCategory::getPid, pid)
                .eq(GoodsCategory::getName, name)
                .ne(StrUtil.isNotBlank(id), GoodsCategory::getId, id);
        return super.exists(wrapper);
    }

    @Override
    public void edit(long merchantNo, String id, CategoryDto dto) {
        if (existsByName(merchantNo, id, dto.getPid(), dto.getName())) {
            throw new CustomException(ResultCode.BAD_REQUEST, String.format("分类名称重复:%s", dto.getName()));
        }
        GoodsCategory entity = findById(merchantNo, id);
        if (entity == null) {
            return;
        }
        BeanUtils.copyProperties(dto, entity);
        entity.setId(id);
        super.updateById(entity);
    }

    @Override
    public void editSort(long merchantNo, String id, CategoryDto dto) {
        GoodsCategory entity = findById(merchantNo, id);
        if (entity == null) {
            return;
        }
        entity.setId(id);
        entity.setSort(dto.getSort());
        super.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void categoryImport(long merchantNo, MultipartFile file) {
        List<CategoryImportDto> list = ExcelUtil.read(file, CategoryImportDto.class);
        if (CollectionUtils.isEmpty(list)) {
            throw new CustomException("检测导入分类内容为空");
        }
        list.forEach(x -> {
            GoodsCategory oneCategoryEntity = findByName(merchantNo, x.getOneCategory(), null);
            if (oneCategoryEntity == null) {
                CategoryDto dto = new CategoryDto();
                dto.setName(x.getOneCategory());
                oneCategoryEntity = create(merchantNo, dto);
            }
            GoodsCategory twoCategoryEntity = findByName(merchantNo, x.getOneCategory(), oneCategoryEntity.getId());
            if (twoCategoryEntity == null) {
                CategoryDto dto = new CategoryDto();
                dto.setPid(oneCategoryEntity.getId());
                dto.setName(x.getTwoCategory());
                create(merchantNo, dto);
            }
        });
    }

    @Override
    public void deleteById(long merchantNo, String id) {
        List<GoodsCategory> list = findByPid(id);
        if (!CollectionUtils.isEmpty(list)) {
            throw new CustomException("当前分类下有子分类，不能删除");
        }
        SpuQuery spuQuery = new SpuQuery();
        spuQuery.setCategoryId(id);
        List<SpuListVo> spus = goodsSpuService.list(merchantNo, spuQuery);
        if (!CollectionUtils.isEmpty(spus)) {
            throw new CustomException("无法删除使用中的分类");
        }
        GoodsCategory entity = new GoodsCategory();
        entity.setId(id);
        entity.setDeleted(CommonDeleted.DELETED.getCode());
        super.updateById(entity);
    }

    @Override
    public GoodsCategory findById(long merchantNo, String id) {
        Wrapper<GoodsCategory> wrapper = new LambdaQueryWrapper<GoodsCategory>()
                .eq(GoodsCategory::getMerchantNo, merchantNo)
                .eq(GoodsCategory::getId, id);
        return super.getOne(wrapper);
    }

    @Override
    public List<GoodsCategory> findByPid(String pid) {
        Wrapper<GoodsCategory> wrapper = new LambdaQueryWrapper<GoodsCategory>()
                .eq(GoodsCategory::getPid, pid);
        return super.list(wrapper);
    }

    @Override
    public PageVo<CategoryVo> page(long merchantNo, CategoryQuery query) {
        query.setLevel(CategoryLevel.ONE.getCode());
        Page<GoodsCategory> tempQuery = new Page<>(query.getPageIndex(), query.getPageSize());
        Wrapper<GoodsCategory> wrapper = new LambdaQueryWrapper<GoodsCategory>()
                .eq(GoodsCategory::getDeleted, CommonDeleted.NOT_DELETED.getCode())
                .and(x -> x.eq(GoodsCategory::getPid, "").or().isNull(GoodsCategory::getPid))
                .and(x -> x.eq(GoodsCategory::getMerchantNo, 0).or().eq(GoodsCategory::getMerchantNo, merchantNo))
                .like(StrUtil.isNotBlank(query.getSearchKey()), GoodsCategory::getName, query.getSearchKey())
                .eq(query.getLevel() != null, GoodsCategory::getLevel, query.getLevel())
                .orderByDesc(GoodsCategory::getSort)
                .orderByDesc(GoodsCategory::getCreateTime);
        IPage<GoodsCategory> page = super.page(tempQuery, wrapper);
        List<CategoryVo> vos = page.getRecords().stream().map(category -> {
            CategoryVo vo = new CategoryVo();
            BeanUtils.copyProperties(category, vo);

            CategoryListQuery subQuery = new CategoryListQuery();
            subQuery.setPid(category.getId());
            subQuery.setDeleted(category.getDeleted());
            subQuery.setLevel(CategoryLevel.TWO.getCode());
            List<GoodsCategory> subList = findAll(merchantNo, subQuery);
            vo.setChildren(
                    subList.stream().map(subCategory -> {
                        CategoryVo subVo = new CategoryVo();
                        BeanUtils.copyProperties(subCategory, subVo);
                        return subVo;
                    }).collect(Collectors.toList())
            );
            return vo;
        }).collect(Collectors.toList());
        return PageVo.result(page, vos);
    }

    @Override
    public List<CategoryTreeVo> tree(long merchantNo) {
        CategoryListQuery query = new CategoryListQuery();
        query.setLevel(CategoryLevel.ONE.getCode());
        query.setDeleted(CommonDeleted.NOT_DELETED.getCode());
        List<GoodsCategory> list = findAll(merchantNo, query);
        return list.stream().map(x -> {
            CategoryListQuery subQuery = new CategoryListQuery();
            subQuery.setPid(x.getId());
            subQuery.setLevel(CategoryLevel.TWO.getCode());
            subQuery.setDeleted(CommonDeleted.NOT_DELETED.getCode());
            List<GoodsCategory> subList = findAll(merchantNo, subQuery);

            List<CategoryTreeVo> childrenes = subList.stream().map(children -> {
                CategoryTreeVo childrenVo = new CategoryTreeVo();
                childrenVo.setValue(children.getId());
                childrenVo.setLabel(children.getName());
                childrenVo.setPid(children.getPid());
                childrenVo.setSort(children.getSort());
                return childrenVo;
            }).collect(Collectors.toList());

            CategoryTreeVo vo = new CategoryTreeVo();
            vo.setValue(x.getId());
            vo.setLabel(x.getName());
            vo.setPid(x.getPid());
            vo.setSort(x.getSort());

            if (CollUtil.isNotEmpty(childrenes)) {
                vo.setChildren(childrenes);
            }
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public GoodsCategory findByName(long merchantNo, String name, String pid) {
        int level = CategoryLevel.TWO.getCode();
        if (StrUtil.isBlank(pid)) {
            level = CategoryLevel.ONE.getCode();
            pid = null;
        }
        Wrapper<GoodsCategory> wrapper = new LambdaQueryWrapper<GoodsCategory>()
                .eq(GoodsCategory::getMerchantNo, merchantNo)
                .eq(GoodsCategory::getName, name)
                .eq(GoodsCategory::getPid, pid)
                .eq(GoodsCategory::getLevel, level);
        return super.getOne(wrapper);
    }

    @Override
    public List<GoodsCategory> findAll(long merchantNo, CategoryListQuery query) {
        QueryWrapper<GoodsCategory> wrapper = new QueryWrapper<>();
        wrapper.eq("1", 1);
        wrapper.lambda().and(x -> x.eq(GoodsCategory::getMerchantNo, merchantNo).or().eq(GoodsCategory::getMerchantNo, 0))
                .eq(StrUtil.isNotBlank(query.getPid()), GoodsCategory::getPid, query.getPid())
                .like(StrUtil.isNotBlank(query.getName()), GoodsCategory::getName, query.getName())
                .eq(query.getLevel() != null, GoodsCategory::getLevel, query.getLevel())
                .eq(query.getDeleted() != null, GoodsCategory::getDeleted, query.getDeleted())
                .orderByAsc(GoodsCategory::getSort)
                .orderByDesc(GoodsCategory::getCreateTime);
        return super.list(wrapper);
    }
}
